use base64::encode;


pub fn encryption(input: String) -> String {
    let key = [0u8; 16];
    let iv = [1u8; 16];
    let input = input.as_str();

    // let mut ans = Vec::new();
    let mut zuc = ZUC::new(&key, &iv);

    let mut tmp  = input.as_bytes().to_vec();
    let mut ans = Vec::new();
    

    //adding padding
    let n = 4 - tmp.len()%4;
    for i in 0..n {
        tmp.push(n as u8);
    }

    for chunk in tmp.chunks(4) {
        let mut tmp_number = u32::from_be_bytes(chunk.try_into().unwrap());
        ans .push(tmp_number^zuc.generate());
    }
    let mut byte_ans = Vec::new();
    for &n in &ans {
        byte_ans.extend_from_slice(&n.to_be_bytes());
    }

    let res = encode(&byte_ans);
  res
}

// pub fn encryption(input: String) -> String {
//     todo!()
// }

// http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=8C41A3AEECCA52B5C0011C8010CF0715


const S0: [u8; 256] = [
    0x3E, 0x72, 0x5B, 0x47, 0xCA, 0xE0, 0x00, 0x33, 0x04, 0xD1, 0x54, 0x98, 0x09, 0xB9, 0x6D, 0xCB,
    0x7B, 0x1B, 0xF9, 0x32, 0xAF, 0x9D, 0x6A, 0xA5, 0xB8, 0x2D, 0xFC, 0x1D, 0x08, 0x53, 0x03, 0x90,
    0x4D, 0x4E, 0x84, 0x99, 0xE4, 0xCE, 0xD9, 0x91, 0xDD, 0xB6, 0x85, 0x48, 0x8B, 0x29, 0x6E, 0xAC,
    0xCD, 0xC1, 0xF8, 0x1E, 0x73, 0x43, 0x69, 0xC6, 0xB5, 0xBD, 0xFD, 0x39, 0x63, 0x20, 0xD4, 0x38,
    0x76, 0x7D, 0xB2, 0xA7, 0xCF, 0xED, 0x57, 0xC5, 0xF3, 0x2C, 0xBB, 0x14, 0x21, 0x06, 0x55, 0x9B,
    0xE3, 0xEF, 0x5E, 0x31, 0x4F, 0x7F, 0x5A, 0xA4, 0x0D, 0x82, 0x51, 0x49, 0x5F, 0xBA, 0x58, 0x1C,
    0x4A, 0x16, 0xD5, 0x17, 0xA8, 0x92, 0x24, 0x1F, 0x8C, 0xFF, 0xD8, 0xAE, 0x2E, 0x01, 0xD3, 0xAD,
    0x3B, 0x4B, 0xDA, 0x46, 0xEB, 0xC9, 0xDE, 0x9A, 0x8F, 0x87, 0xD7, 0x3A, 0x80, 0x6F, 0x2F, 0xC8,
    0xB1, 0xB4, 0x37, 0xF7, 0x0A, 0x22, 0x13, 0x28, 0x7C, 0xCC, 0x3C, 0x89, 0xC7, 0xC3, 0x96, 0x56,
    0x07, 0xBF, 0x7E, 0xF0, 0x0B, 0x2B, 0x97, 0x52, 0x35, 0x41, 0x79, 0x61, 0xA6, 0x4C, 0x10, 0xFE,
    0xBC, 0x26, 0x95, 0x88, 0x8A, 0xB0, 0xA3, 0xFB, 0xC0, 0x18, 0x94, 0xF2, 0xE1, 0xE5, 0xE9, 0x5D,
    0xD0, 0xDC, 0x11, 0x66, 0x64, 0x5C, 0xEC, 0x59, 0x42, 0x75, 0x12, 0xF5, 0x74, 0x9C, 0xAA, 0x23,
    0x0E, 0x86, 0xAB, 0xBE, 0x2A, 0x02, 0xE7, 0x67, 0xE6, 0x44, 0xA2, 0x6C, 0xC2, 0x93, 0x9F, 0xF1,
    0xF6, 0xFA, 0x36, 0xD2, 0x50, 0x68, 0x9E, 0x62, 0x71, 0x15, 0x3D, 0xD6, 0x40, 0xC4, 0xE2, 0x0F,
    0x8E, 0x83, 0x77, 0x6B, 0x25, 0x05, 0x3F, 0x0C, 0x30, 0xEA, 0x70, 0xB7, 0xA1, 0xE8, 0xA9, 0x65,
    0x8D, 0x27, 0x1A, 0xDB, 0x81, 0xB3, 0xA0, 0xF4, 0x45, 0x7A, 0x19, 0xDF, 0xEE, 0x78, 0x34, 0x60,
];

const S1: [u8; 256] = [
    0x55, 0xC2, 0x63, 0x71, 0x3B, 0xC8, 0x47, 0x86, 0x9F, 0x3C, 0xDA, 0x5B, 0x29, 0xAA, 0xFD, 0x77,
    0x8C, 0xC5, 0x94, 0x0C, 0xA6, 0x1A, 0x13, 0x00, 0xE3, 0xA8, 0x16, 0x72, 0x40, 0xF9, 0xF8, 0x42,
    0x44, 0x26, 0x68, 0x96, 0x81, 0xD9, 0x45, 0x3E, 0x10, 0x76, 0xC6, 0xA7, 0x8B, 0x39, 0x43, 0xE1,
    0x3A, 0xB5, 0x56, 0x2A, 0xC0, 0x6D, 0xB3, 0x05, 0x22, 0x66, 0xBF, 0xDC, 0x0B, 0xFA, 0x62, 0x48,
    0xDD, 0x20, 0x11, 0x06, 0x36, 0xC9, 0xC1, 0xCF, 0xF6, 0x27, 0x52, 0xBB, 0x69, 0xF5, 0xD4, 0x87,
    0x7F, 0x84, 0x4C, 0xD2, 0x9C, 0x57, 0xA4, 0xBC, 0x4F, 0x9A, 0xDF, 0xFE, 0xD6, 0x8D, 0x7A, 0xEB,
    0x2B, 0x53, 0xD8, 0x5C, 0xA1, 0x14, 0x17, 0xFB, 0x23, 0xD5, 0x7D, 0x30, 0x67, 0x73, 0x08, 0x09,
    0xEE, 0xB7, 0x70, 0x3F, 0x61, 0xB2, 0x19, 0x8E, 0x4E, 0xE5, 0x4B, 0x93, 0x8F, 0x5D, 0xDB, 0xA9,
    0xAD, 0xF1, 0xAE, 0x2E, 0xCB, 0x0D, 0xFC, 0xF4, 0x2D, 0x46, 0x6E, 0x1D, 0x97, 0xE8, 0xD1, 0xE9,
    0x4D, 0x37, 0xA5, 0x75, 0x5E, 0x83, 0x9E, 0xAB, 0x82, 0x9D, 0xB9, 0x1C, 0xE0, 0xCD, 0x49, 0x89,
    0x01, 0xB6, 0xBD, 0x58, 0x24, 0xA2, 0x5F, 0x38, 0x78, 0x99, 0x15, 0x90, 0x50, 0xB8, 0x95, 0xE4,
    0xD0, 0x91, 0xC7, 0xCE, 0xED, 0x0F, 0xB4, 0x6F, 0xA0, 0xCC, 0xF0, 0x02, 0x4A, 0x79, 0xC3, 0xDE,
    0xA3, 0xEF, 0xEA, 0x51, 0xE6, 0x6B, 0x18, 0xEC, 0x1B, 0x2C, 0x80, 0xF7, 0x74, 0xE7, 0xFF, 0x21,
    0x5A, 0x6A, 0x54, 0x1E, 0x41, 0x31, 0x92, 0x35, 0xC4, 0x33, 0x07, 0x0A, 0xBA, 0x7E, 0x0E, 0x34,
    0x88, 0xB1, 0x98, 0x7C, 0xF3, 0x3D, 0x60, 0x6C, 0x7B, 0xCA, 0xD3, 0x1F, 0x32, 0x65, 0x04, 0x28,
    0x64, 0xBE, 0x85, 0x9B, 0x2F, 0x59, 0x8A, 0xD7, 0xB0, 0x25, 0xAC, 0xAF, 0x12, 0x03, 0xE2, 0xF2,
];

const D: [u32; 16] = [
    0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF, 0x4D78, 0x2F13, 0x6BC4, 0x1AF1,
    0x5E26, 0x3C4D, 0x789A, 0x47AC,
];
struct LFSR {
    reg: [u32; 16],
}
// // 按位加法，保证结果在 31 位范围内
// fn addition_uint31(a: u32, b: u32) -> u32 {
//     let c = a + b;
//     (c & 0x7FFFFFFF) + (c >> 31)
// }
// 按位加法，保证结果在 31 位范围内
fn add(a: u32, b: u32) -> u32 {
    a.wrapping_add(b)
}

fn add_m31(a: u32, b: u32) -> u32 {
    let c = add(a, b);
    (c & 0x7FFF_FFFF) + (c >> 31)
}
fn rol(x: u32, n: u32) -> u32 {
    x.rotate_left(n)
}
// 非线性函数 l1
fn l1(x: u32) -> u32 {
    x ^ rol(x, 2) ^ rol(x, 10) ^ rol(x, 18) ^ rol(x, 24)
}
fn cheng_m31(a: u32, b: u32) -> u32 {
    ((u64::from(a) * u64::from(b)) % ((1 << 31) - 1)) as u32
}
// 非线性函数 l2
fn l2(x: u32) -> u32 {
    x ^ rol(x, 8) ^ rol(x, 14) ^ rol(x, 22) ^ rol(x, 30)
}
struct ZUC {
    lfsr: LFSR,
    br: BR,
    f: F,
}
impl ZUC {
    fn new(key: &[u8; 16], iv: &[u8; 16]) -> Self {
        let lfsr = LFSR::init(key, iv);
        // for i in lfsr.reg {
        //     print!("{:x} ",i);
        // }
        // println!("");
        let mut zuc = Self {
            lfsr,
            br: BR {
                X0: 0,
                X1: 0,
                X2: 0,
                X3: 0,
            },
            f: F { R1: 0, R2: 0 },
        };
        for _ in 0..32 {
            zuc.bit_reconstruction();
            let w = zuc.f();
            zuc.lfsr_with_initialization_mode(w >> 1);
        }
        zuc.generate();
        zuc
    }
    fn bit_reconstruction(&mut self) {
        self.br = self.lfsr.BitReconstruction();
    }
    fn f(&mut self) -> u32 {
        let w = add(self.br.X0 ^ self.f.R1, self.f.R2);
        let w1 = add(self.f.R1, self.br.X1);
        let w2 = self.f.R2 ^ self.br.X2;
        self.f.R1 = translation_S_box(l1((w1 << 16) | (w2 >> 16)));
        self.f.R2 = translation_S_box(l2((w2 << 16) | (w1 >> 16)));

        w
    }

    fn lfsr_with_initialization_mode(&mut self, u: u32) {
        self.lfsr.LFSRInitialisationMode(u);
    }

    fn lfsr_with_work_mode(&mut self) {
        self.lfsr.LFSRWithWorkMode();
    }

    pub fn generate(&mut self) -> u32 {
        self.bit_reconstruction();
        let z = self.f() ^ self.br.X3;
        self.lfsr_with_work_mode();
        z
    }
}
impl LFSR {
    fn init(k: &[u8; 16], v: &[u8; 16]) -> Self {
        let regs = [
            (((k[0] as u32) << 23) | ((D[0]) << 8) | (v[0] as u32)),
            (((k[1] as u32) << 23) | ((D[1]) << 8) | (v[1] as u32)),
            (((k[2] as u32) << 23) | ((D[2]) << 8) | (v[2] as u32)),
            (((k[3] as u32) << 23) | ((D[3]) << 8) | (v[3] as u32)),
            (((k[4] as u32) << 23) | ((D[4]) << 8) | (v[4] as u32)),
            (((k[5] as u32) << 23) | ((D[5]) << 8) | (v[5] as u32)),
            (((k[6] as u32) << 23) | ((D[6]) << 8) | (v[6] as u32)),
            (((k[7] as u32) << 23) | ((D[7]) << 8) | (v[7] as u32)),
            (((k[8] as u32) << 23) | ((D[8]) << 8) | (v[8] as u32)),
            (((k[9] as u32) << 23) | ((D[9]) << 8) | (v[9] as u32)),
            (((k[10] as u32) << 23) | ((D[10]) << 8) | (v[10] as u32)),
            (((k[11] as u32) << 23) | ((D[11]) << 8) | (v[11] as u32)),
            (((k[12] as u32) << 23) | ((D[12]) << 8) | (v[12] as u32)),
            (((k[13] as u32) << 23) | ((D[13]) << 8) | (v[13] as u32)),
            (((k[14] as u32) << 23) | ((D[14]) << 8) | (v[14] as u32)),
            (((k[15] as u32) << 23) | ((D[15]) << 8) | (v[15] as u32)),
        ];
        // println!("{:?}",regs);
        Self { reg: regs }
    }

    fn LFSRInitialisationMode(&mut self, u: u32) {
        // 1

        // println!("from u {}",u);
        // println!("from u {:032b}\n\n",u);
        // (1+ 2^8) * s0 mod (2^31-1)
        let v = {
            let tmp1 = cheng_m31(1 << 15, self.reg[15]);
            let tmp2 = cheng_m31(1 << 17, self.reg[13]);
            let tmp3 = cheng_m31(1 << 21, self.reg[10]);
            let tmp4 = cheng_m31(1 << 20, self.reg[4]);
            let tmp5 = cheng_m31((1 << 8) + 1, self.reg[0]);
            add_m31(tmp1, add_m31(tmp2, add_m31(tmp3, add_m31(tmp4, tmp5))))
        };
        //2
        let mut s16 = add_m31(v, u);

        //3
        if s16 == 0 {
            s16 = (1 << 31) - 1;
        }
        // println!("{:?}", self.reg);
        //4
        self.reg[0] = self.reg[1];
        self.reg[1] = self.reg[2];
        self.reg[2] = self.reg[3];
        self.reg[3] = self.reg[4];
        self.reg[4] = self.reg[5];
        self.reg[5] = self.reg[6];
        self.reg[6] = self.reg[7];
        self.reg[7] = self.reg[8];
        self.reg[8] = self.reg[9];
        self.reg[9] = self.reg[10];
        self.reg[10] = self.reg[11];
        self.reg[11] = self.reg[12];
        self.reg[12] = self.reg[13];
        self.reg[13] = self.reg[14];
        self.reg[14] = self.reg[15];
        self.reg[15] = s16;
    }

    fn LFSRWithWorkMode(&mut self) {
        //1
        let mut s16 = {
            let tmp1 = cheng_m31(1 << 15, self.reg[15]);
            let tmp2 = cheng_m31(1 << 17, self.reg[13]);
            let tmp3 = cheng_m31(1 << 21, self.reg[10]);
            let tmp4 = cheng_m31(1 << 20, self.reg[4]);
            let tmp5 = cheng_m31((1 << 8) + 1, self.reg[0]);
            add_m31(tmp1, add_m31(tmp2, add_m31(tmp3, add_m31(tmp4, tmp5))))
        };
        //2
        if s16 == 0 {
            s16 = (1 << 31) - 1;
        }

        //3
        self.reg[0] = self.reg[1];
        self.reg[1] = self.reg[2];
        self.reg[2] = self.reg[3];
        self.reg[3] = self.reg[4];
        self.reg[4] = self.reg[5];
        self.reg[5] = self.reg[6];
        self.reg[6] = self.reg[7];
        self.reg[7] = self.reg[8];
        self.reg[8] = self.reg[9];
        self.reg[9] = self.reg[10];
        self.reg[10] = self.reg[11];
        self.reg[11] = self.reg[12];
        self.reg[12] = self.reg[13];
        self.reg[13] = self.reg[14];
        self.reg[14] = self.reg[15];
        self.reg[15] = s16;
    }

    fn BitReconstruction(&self) -> BR {
        // println!("{:032b}",self.reg[15]);
        // println!("{:032b}",self.reg[14]);

        // println!("{:032b}",(((self.reg[15] >> 15) & (1 << 17 - 1)) << 16));

        // println!("{:032b}",(self.reg[14] & (1 << 17 - 1)) );
        let x0 = ((self.reg[15] & 0x7FFF_8000) << 1) | (self.reg[14] & 0xFFFF);
        let x1 = ((self.reg[11] & 0xFFFF) << 16) | (self.reg[9] >> 15);
        let x2 = ((self.reg[7] & 0xFFFF) << 16) | (self.reg[5] >> 15);
        let x3 = ((self.reg[2] & 0xFFFF) << 16) | (self.reg[0] >> 15);
        // println!("{}",x0);
        // println!("{}",x1);
        // println!("{}",x2);
        // println!("{}",x3);

        // println!("\n\n\n\n");
        BR {
            X0: x0,
            X1: x1,
            X2: x2,
            X3: x3,
        }
    }
}
struct F {
    R1: u32,
    R2: u32,
}

// // 构造 32 位无符号整数
// fn make_uint32(a: u8, b: u8, c: u8, d: u8) -> u32 {
//     ((a as u32) << 24) | ((b as u32) << 16) | ((c as u32) << 8) | (d as u32)
// }

// // 构造 31 位无符号整数
// fn make_uint31(a: u8, b: u8, c: u8) -> u32 {
//     (((a as u32) << 23) & 0x7FFFFFFF) | (((b as u32) << 8) & 0x7FFFFFFF) | (c as u32)
// }

fn translation_S_box(x: u32) -> u32 {
    let x = x.to_be_bytes();
    let y = [
        S0[x[0] as usize],
        S1[x[1] as usize],
        S0[x[2] as usize],
        S1[x[3] as usize],
    ];
    u32::from_be_bytes(y)

    // let tmp = x0 | x1;
    // let tmp2: u32 = tmp >> 16;
    // tmp | tmp2
}

#[derive(Debug)]
struct BR {
    X0: u32,
    X1: u32,
    X2: u32,
    X3: u32,
}
impl Iterator for ZUC {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        Some(self.generate())
    }
}